import sys
from PySide6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, QFormLayout, QWidget, QLineEdit, QPushButton, QTreeView, QFileDialog, QMessageBox, QFileSystemModel, QTreeWidgetItem, QTreeWidget, QProgressBar,QInputDialog,QFrame
from PySide6.QtCore import Qt, QDir, QFileInfo, QThread, Signal, Slot, QTimer
from qfluentwidgets import LineEdit,TreeView,PushButton,PrimaryPushButton,MessageBox,ComboBox,ToolButton,FluentIcon,ProgressBar
import pyzipper  # 使用 pyzipper 进行加密压缩
import pathlib
import sqlite3
import time
import re

class ConfigManager:
    def __init__(self, db_path="config.db"):
        self.db_path = db_path
        self.conn = sqlite3.connect(self.db_path)
        self.create_table()

    def create_table(self):
        with self.conn:
            self.conn.execute('''
                CREATE TABLE IF NOT EXISTS config (
                    key TEXT PRIMARY KEY,
                    value TEXT
                )
            ''')

    def get_config(self, key, default=None):
        cursor = self.conn.cursor()
        cursor.execute("SELECT value FROM config WHERE key=?", (key,))
        result = cursor.fetchone()
        return result[0] if result else default

    def set_config(self, key, value):
        with self.conn:
            self.conn.execute('''
                INSERT OR REPLACE INTO config (key, value) VALUES (?, ?)
            ''', (key, value))

    def close(self):
        self.conn.close()

class PackagerWorker(QThread):
    progress_updated = Signal(int, str)  # 信号：进度值和当前文件路径
    packing_finished = Signal(list, list)  # 信号：打包完成，传递打包和跳过的文件列表
    cancelled = Signal()  # 信号：取消操作

    def __init__(self, path, target_extensions, password="llgoll"):  # 添加默认密码参数
        super().__init__()
        self.path = path
        self.target_extensions = target_extensions
        self.is_cancelled = False
        self.password = password  # 设置默认密码

    def run(self):
        files_to_pack = [file_path for file_path in self.path.rglob('*') if file_path.is_file() and any(file_path.suffix.lower() == ext for ext in self.target_extensions)]

        if not files_to_pack:
            self.packing_finished.emit([], [])
            return

        packed_files = []
        skipped_files = []

        backup_dir = self.path / "backup"
        backup_dir.mkdir(exist_ok=True)

        for i, file_path in enumerate(files_to_pack):
            if self.is_cancelled:
                self.cancelled.emit()
                self.packing_finished.emit([], [])  # 发出打包完成信号，确保主线程恢复按钮状态
                return

            mtime = file_path.stat().st_mtime
            mtime_str = time.strftime("%Y%m%d_%H%M%S", time.localtime(mtime))
            base_name = file_path.stem
            zip_filename = f"{base_name}_{mtime_str}.lgzip"
            zip_path = backup_dir / zip_filename

            if not zip_path.exists():  # 判断是否已打包
                with pyzipper.AESZipFile(zip_path, 'w', compression=pyzipper.ZIP_LZMA, encryption=pyzipper.WZ_AES) as zipf:
                    relative_path = file_path.relative_to(self.path)
                    zipf.setpassword(self.password.encode())  # 设置密码
                    zipf.write(file_path, arcname=relative_path)
                packed_files.append((str(file_path), str(zip_path), "成功"))
            else:
                skipped_files.append((str(file_path), "已存在", "跳过"))               

            # 更新进度条
            self.progress_updated.emit(i + 1, str(file_path))

        # 完成进度条
        self.packing_finished.emit(packed_files, skipped_files)

    def cancel(self):
        self.is_cancelled = True

class PackagerApp(QFrame):
    def __init__(self,text: str, parent=None):
        super().__init__(parent=parent)
        self.setObjectName(text.replace(' ', '-'))

        self.config_manager = ConfigManager()
        self.target_extensions = self.parse_extensions(self.config_manager.get_config("target_extensions", ".txt"))
        
        # 创建主部件和布局
        main_layout = QVBoxLayout()

        # 创建顶部水平布局，包含路径输入框、浏览按钮和设置按钮
        top_layout = QHBoxLayout()

        # 路径输入框
        self.path_input = LineEdit(self)
        self.path_input.setPlaceholderText("请输入或选择路径...")
        self.path_input.setReadOnly(True)
        top_layout.addWidget(self.path_input)

        # 浏览按钮
        browse_button = PushButton("浏览", self)
        browse_button.clicked.connect(self.browse_folder)
        top_layout.addWidget(browse_button)

        # 设置按钮
        settings_button = ToolButton(FluentIcon.SETTING, self)
        settings_button.clicked.connect(self.open_settings)
        top_layout.addWidget(settings_button)

        # 将顶部水平布局添加到主布局
        main_layout.addLayout(top_layout)

        # 创建按钮水平布局，打包及取消按钮
        button_layout = QHBoxLayout()

        # 打包按钮
        self.pack_button = PrimaryPushButton(FluentIcon.UPDATE,"备份")
        # PushButton("打包", clicked=self.start_packing)
        self.pack_button.clicked.connect(self.start_packing)
        button_layout.addWidget(self.pack_button)

        # 取消按钮
        self.cancel_button = PushButton("取消")
        self.cancel_button.setEnabled(False)
        self.cancel_button.clicked.connect(self.cancel_packing)
        button_layout.addWidget(self.cancel_button)

        # 将顶部水平布局添加到主布局
        main_layout.addLayout(button_layout)

        # 进度条
        self.progress_bar = ProgressBar(self)
        self.progress_bar.setValue(0)
        main_layout.addWidget(self.progress_bar)

        # TreeView 用于显示文件夹结构
        self.tree_view = TreeView()
        self.file_model = QFileSystemModel()
        self.file_model.setRootPath("")
        self.tree_view.setModel(self.file_model)
        self.update_tree_view_border()
        main_layout.addWidget(self.tree_view)

        # TreeWidget 用于显示打包结果
        self.results_tree = QTreeWidget()
        self.results_tree.setHeaderLabels(["原文件路径", "打包文件路径", "结果"])        
        main_layout.addWidget(self.results_tree)

        # 设置主部件和布局
        self.setLayout(main_layout)

        # 工作线程
        self.worker_thread = None

        # 保存打开的 QFileDialog 实例
        self.file_dialog = None

    def parse_extensions(self, extensions_str):
        # 使用正则表达式过滤并规范化扩展名
        valid_extensions = []
        for ext in extensions_str.split(","):
            ext = ext.strip().lower()
            if not ext.startswith('.'):
                ext = '.' + ext
            if re.match(r'^\.[a-zA-Z0-9_]+$', ext):
                valid_extensions.append(ext)
        return valid_extensions

    def preprocess_extensions(self, extensions_str):
        # 将中文逗号替换为英文逗号，并去除多余的空格
        return extensions_str.replace('，', ',').strip()

    def browse_folder(self):
        # 打开 QFileDialog 选择文件夹
        self.file_dialog = QFileDialog(self, "选择文件夹")
        self.file_dialog.setFileMode(QFileDialog.Directory)
        self.file_dialog.setOption(QFileDialog.ShowDirsOnly, True)
        self.file_dialog.finished.connect(self.on_file_dialog_finished)  # 连接 finished 信号
        self.file_dialog.show()

    @Slot(int)
    def on_file_dialog_finished(self, result):
        if result == QFileDialog.Accepted:
            folder_path = self.file_dialog.selectedFiles()[0]
            self.update_path(folder_path)

    def update_path(self, folder_path):
        self.path_input.setText(folder_path)
        self.update_tree_view(pathlib.Path(folder_path))

    def update_tree_view(self, folder_path):
        self.file_model.setRootPath(str(folder_path))
        self.tree_view.setRootIndex(self.file_model.index(str(folder_path)))

    def start_packing(self):
        # 获取路径输入框的内容并去除前后空格
        path_str = self.path_input.text().strip()

        # 检查路径是否为空
        if not path_str:
            QMessageBox.warning(self, "警告", "路径不能为空，请输入或选择有效的路径。")
            return

        path = pathlib.Path(path_str)
        if not path.is_dir():
            QMessageBox.critical(self, "错误", "无效的路径，请选择有效的文件夹。")
            return

        # 获取符合条件的文件列表
        files_to_pack = [file_path for file_path in path.rglob('*') if file_path.is_file() and any(file_path.suffix.lower() == ext for ext in self.target_extensions)]

        if not files_to_pack:
            QMessageBox.information(self, "提示", "没有找到符合条件的文件。")
            return

        # 禁用打包按钮，启用取消按钮
        self.pack_button.setEnabled(False)
        self.cancel_button.setEnabled(True)

        # 启动工作线程
        self.worker_thread = PackagerWorker(path, self.target_extensions, password="llgoll")  # 传递默认密码
        self.worker_thread.progress_updated.connect(self.update_progress)
        self.worker_thread.packing_finished.connect(self.on_packing_finished)
        self.worker_thread.cancelled.connect(self.on_packing_cancelled)
        self.worker_thread.start()

        # 初始化进度条
        self.progress_bar.setMaximum(len(files_to_pack))
        self.progress_bar.setValue(0)

    def cancel_packing(self):
        if self.worker_thread:
            self.worker_thread.cancel()
            self.cancel_button.setEnabled(False)

    @Slot(int, str)
    def update_progress(self, value, current_file):
        self.progress_bar.setValue(value)

    @Slot(list, list)
    def on_packing_finished(self, packed_files, skipped_files):
        # 更新结果列表
        
        for original, packed, status in packed_files:
            item = QTreeWidgetItem(self.results_tree, [original, packed, status])
        for original, reason, status in skipped_files:
            item = QTreeWidgetItem(self.results_tree, [original, "无", status])

        # 更新TreeView以反映新创建的ZIP文件
        self.update_tree_view(pathlib.Path(self.path_input.text().strip()))

        # 提供反馈信息
        if packed_files:
            QMessageBox.information(self, "成功", f"共打包 {len(packed_files)} 个文件。")
        if skipped_files:
            QMessageBox.warning(self, "提示", f"共跳过 {len(skipped_files)} 个文件，因为它们已经存在。")

        # 恢复按钮状态
        self.pack_button.setEnabled(True)
        self.cancel_button.setEnabled(False)

    @Slot()
    def on_packing_cancelled(self):
        QMessageBox.warning(self, "取消", "打包操作已取消。")
        self.pack_button.setEnabled(True)
        self.cancel_button.setEnabled(False)

    def open_settings(self):
        text, ok = QInputDialog.getText(self, '设置目标扩展名', '输入目标文件扩展名（例如 .txt,.py）:', text=','.join(self.target_extensions))
        if ok and text.strip():
            # 预处理用户输入的扩展名，将中文逗号替换为英文逗号
            cleaned_text = self.preprocess_extensions(text.strip())

            # 检查并清理用户输入的扩展名
            cleaned_extensions = self.parse_extensions(cleaned_text)
            if not cleaned_extensions:
                QMessageBox.critical(self, "错误", "输入的扩展名格式不正确，请确保每个扩展名以点号开头且只包含字母、数字和下划线。")
                return

            self.target_extensions = cleaned_extensions
            self.config_manager.set_config("target_extensions", ','.join(self.target_extensions))
            QMessageBox.information(self, "设置", f"目标扩展名已设置为: {', '.join(self.target_extensions)}")

    # def check_resources(self):
    #     # 这里可以添加一些逻辑来检查是否有未完成的任务
    #     # 例如，检查是否有正在运行的文件操作或网络请求
    #     pass

    def update_tree_view_border(self):
        # 获取当前样式表
        current_style = self.tree_view.styleSheet()  
        
        # 定义新的边框样式
        new_style = """
            QTreeView {
                border: 1px solid #EAEAEA; /* 深色模式下的边框颜色 */
                border-radius: 2px;
            }
        """
        
        # 合并样式
        combined_style = current_style + new_style if current_style else new_style
        self.tree_view.setStyleSheet(combined_style)

    def closeEvent(self, event):
        # 确保所有资源被正确释放
        self.config_manager.close()


        # 如果有正在运行的工作线程，等待其结束
        if self.worker_thread and self.worker_thread.isRunning():
            self.worker_thread.cancel()  # 尝试取消线程
            self.worker_thread.wait()  # 等待线程结束

        # 关闭 QFileDialog（如果有）
        if self.file_dialog and self.file_dialog.isVisible():
            self.file_dialog.reject()  # 关闭对话框

        # 确保所有子窗口和对话框都被关闭
        for child in self.children():
            if isinstance(child, (QMessageBox, QFileDialog)):
                child.close()

        # 接受关闭事件
        event.accept()
